/**
 *******************************************************************************************************************************************
 * @file        TP_RTP01.c
 * @brief       本例程为触摸 IC 驱动: RTP01
 * @details     /
 * @since       Change Logs:
 * Date         Author       Notes
 * 2023-08-23   lzh          the first version
 * @remark      本驱动可作为独立模块而应用
 * 目前将 各型号触摸驱动 统一嵌入例程 dev_touch 模块, 故此处声明引用 dev_touch.h 以快速适配具体硬件版本
 * 如本触摸驱动想不依赖于 dev_touch 模块, 用户只需移除 dev_touch.h , 重新适配 Static_GPIO/PORT/Pin 具体端口, 并实现 Static_IIC_xxx() 函数
 *******************************************************************************************************************************************
 * @attention
 *
 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
 * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
 * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
 * -ECTION WITH THEIR PRODUCTS.
 *
 * @copyright   2012 Synwit Technology
 *******************************************************************************************************************************************
 */
#include <string.h>
#include "TP_RTP01.h"

/*******************************************************************************************************************************************
 * Private Define
 *******************************************************************************************************************************************/
#define Static_INT_TRIG_ENABLE /**< INT 边沿触发使能(由 dev_touch 模块统一处理) */

#include "dev_systick.h"
/** 实现 ms 级延时 */
#define Static_Delay_MS(ms)     systick_delay_ms(ms)

#define Static_GPIO_RST         TP_GPIO_RST
#define Static_PIN_RST          TP_PIN_RST

#define Static_GPIO_INT         TP_GPIO_INT
#define Static_PIN_INT          TP_PIN_INT
#define Static_INT_IRQn         TP_INT_IRQn
#define Static_INT_Handler      TP_INT_Handler

#if (SWM34S_LCM_PCBV == SWM34SCE_PIN48_A2)

#define Static_GPIO_SCL         TP_GPIO_SCL
#define Static_PIN_SCL          TP_PIN_SCL

#define Static_GPIO_SDA         TP_GPIO_SDA
#define Static_PIN_SDA          TP_PIN_SDA

#define Static_IIC_Init()       do { \
                                GPIO_Init(Static_GPIO_SCL, Static_PIN_SCL, 1, 1, 0, 0); \
                                GPIO_Init(Static_GPIO_SDA, Static_PIN_SDA, 1, 1, 0, 0); \
                                GPIO_AtomicSetBit(Static_GPIO_SCL, Static_PIN_SCL); \
                                GPIO_AtomicSetBit(Static_GPIO_SDA, Static_PIN_SDA); \
                                } while (0)

#include "dev_io_i2c.h" /* 软件 IIC 实现 */

#define Static_IIC_Start(addr)          io_i2c_start(addr, 1)
#define Static_IIC_Read(ack)            io_i2c_read(ack, 1)
#define Static_IIC_Write(data)          io_i2c_write(data, 1)
#define Static_IIC_Stop()               io_i2c_stop(1)

#else /* 硬件 IIC */

#define Static_PORT_SCL         TP_PORT_SCL
#define Static_PIN_SCL          TP_PIN_SCL
#define Static_PIN_SCL_FUN      TP_PIN_SCL_FUN

#define Static_PORT_SDA         TP_PORT_SDA
#define Static_PIN_SDA          TP_PIN_SDA
#define Static_PIN_SDA_FUN      TP_PIN_SDA_FUN

#define Static_IIC_X            TP_I2C_X

#define Static_IIC_Init()       do { \
                                I2C_InitStructure I2C_initStruct; \
                                PORT_Init(Static_PORT_SCL, Static_PIN_SCL, Static_PIN_SCL_FUN, 1); \
                                Static_PORT_SCL->PULLU |= (1 << Static_PIN_SCL); \
                                Static_PORT_SCL->OPEND |= (1 << Static_PIN_SCL); \
                                PORT_Init(Static_PORT_SDA, Static_PIN_SDA, Static_PIN_SDA_FUN, 1); \
                                Static_PORT_SDA->PULLU |= (1 << Static_PIN_SDA); \
                                Static_PORT_SDA->OPEND |= (1 << Static_PIN_SDA); \
                                \
                                I2C_initStruct.Master = 1; \
                                I2C_initStruct.Addr10b = 0; \
                                I2C_initStruct.MstClk = 400000; \
                                I2C_initStruct.TXEmptyIEn = 0; \
                                I2C_initStruct.RXNotEmptyIEn = 0; \
                                I2C_Init(Static_IIC_X, &I2C_initStruct); \
                                I2C_Open(Static_IIC_X); \
                                } while (0)

#define Static_IIC_Start(addr)          I2C_Start(Static_IIC_X, addr, 1)
#define Static_IIC_Read(ack)            I2C_Read(Static_IIC_X, ack, 1)
#define Static_IIC_Write(data)          I2C_Write(Static_IIC_X, data, 1)
#define Static_IIC_Stop()               I2C_Stop(Static_IIC_X, 1)

#endif

/** 按 8 位地址的方式定义(7 bit 器件地址 + 1 bit 读写控制位) */
#define RTPx_ADDR       0x90

/* GT9xx 部分寄存器定义 */
#define RTPx_CTRL       0x8040  /**< 控制寄存器 */
#define RTPx_CFGS       0x8047  /**< 配置寄存器 */
#define RTPx_CHECK      0x80FF  /**< 校验和寄存器 */
#define RTPx_PID        0x8140  /**< 产品ID寄存器 */

#define RTPx_GSTID      0x814E  /**< 当前检测到的触摸情况 */
#define RTPx_TP1        0x8150  /**< 第一个触摸点数据地址 */
#define RTPx_TP2        0x8158  /**< 第二个触摸点数据地址 */
#define RTPx_TP3        0x8160  /**< 第三个触摸点数据地址 */
#define RTPx_TP4        0x8168  /**< 第四个触摸点数据地址 */
#define RTPx_TP5        0x8170  /**< 第五个触摸点数据地址 */

#define DRV_W       0X90
#define DRV_R       0X91
#define cmd_x       0XC4
#define cmd_y       0XD4
#define cmd_yl_min  0XE4
#define cmd_yl_max  0XF3

/*******************************************************************************************************************************************
 * Private Constant
 *******************************************************************************************************************************************/
static const uint16_t RTPx_TP_Tab[5] = {RTPx_TP1, RTPx_TP2, RTPx_TP3, RTPx_TP4, RTPx_TP5};

/*********************************************************************************
 * 如果需要更新触摸配置请定义宏 UPDATE_CFG, 否则默认无须更新, 请在更新前咨询 TP 厂家
**********************************************************************************/
//#define UPDATE_CFG /**< 一般情形下,请不要打开该宏!请不要打开该宏!请不要打开该宏! 有可能会把 TP 芯片变砖, 变砖后请自行联系 TP 供应商. */
#ifdef UPDATE_CFG
/* 配置文件的版本号(新下发的配置版本号大于原版本，或等于原版本号但配置内容有变化时保存，
 * 版本号版本正常范围：'A'~'Z',发送 0x00 则将版本号初始化为'A')
 */
static uint8_t RTPx_CFG_Tab[] =
{
    0x00, 0xE0, 0x01, 0x10, 0x01, 0x0A, 0x0D, 0x00,
    0x01, 0x08, 0x28, 0x05, 0x50, 0x32, 0x03, 0x05,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x89, 0x2A, 0x0B, 0x17, 0x15,
    0x31, 0x0D, 0x00, 0x00, 0x03, 0xBA, 0x04, 0x2D,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
    0x00, 0x00, 0x00, 0x0F, 0x94, 0x94, 0xC5, 0x02,
    0x07, 0x00, 0x00, 0x04, 0x8D, 0x13, 0x00, 0x5C,
    0x1E, 0x00, 0x3C, 0x30, 0x00, 0x29, 0x4C, 0x00,
    0x1F, 0x78, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C, 0x0A, 0x08,
    0x06, 0x04, 0x02, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
    0x04, 0x06, 0x08, 0x0A, 0x0F, 0x10, 0x12, 0x16,
    0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
    0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static bool rtpx_update_cfg(void);
#endif

/*******************************************************************************************************************************************
 * Private Prototype
 *******************************************************************************************************************************************/
static void iic_delay(void);
static uint8_t tp_read_regs(uint16_t reg, uint8_t *buf, uint8_t len);
static uint8_t tp_write_regs(uint16_t reg, uint8_t *buf, uint8_t len);

/*******************************************************************************************************************************************
 * Public Function
 *******************************************************************************************************************************************/
/**
 * @brief   初始化 TP_IC
 * @param   /
 * @retval  0     : success
 * @retval  other : error code
 */
uint8_t rtpx_init(void)
{
    uint8_t temp[5] = {0};
    Static_IIC_Init();
    GPIO_Init(Static_GPIO_INT, Static_PIN_INT, 0, 1, 0, 0); /* 设置下拉, 选中 IIC 地址 */
    GPIO_Init(Static_GPIO_RST, Static_PIN_RST, 1, 1, 0, 0); /* 复位 */
    GPIO_AtomicClrBit(Static_GPIO_RST, Static_PIN_RST);
    Static_Delay_MS(10);
    GPIO_AtomicSetBit(Static_GPIO_RST, Static_PIN_RST);
    Static_Delay_MS(60);
    //tp_read_regs(RTPx_PID, temp, 4);
    //printf("Touch IC id:%s\r\n", temp);
    #ifdef UPDATE_CFG /* 更新触摸芯片配置 */
    rtpx_update_cfg();
    #endif
    #ifdef Static_INT_TRIG_ENABLE
    /* 中断方式选用边沿触发，则需要在 TP_IC 初始化中设置 TP 芯片的扫描方式为中断触发，
     * 如此才能使得长时间按压时不断触发 TP_INT 边沿脉冲信号
     */
    GPIO_Init(Static_GPIO_INT, Static_PIN_INT, 0, 1, 0, 0);
    EXTI_Init(Static_GPIO_INT, Static_PIN_INT, EXTI_FALL_EDGE); /* EXTI_FALL_EDGE - 下降沿触发 / EXTI_RISE_EDGE - 上升沿触发 */
    NVIC_EnableIRQ(Static_INT_IRQn);
    EXTI_Open(Static_GPIO_INT, Static_PIN_INT);
    #endif
   // printf("TP_RTP01 is Ready!\r\n");
    return 1;
}

#if 0 /* 触摸 INT 外部中断服务子程序统一由 irq_handler 模块处理 */
void Static_INT_Handler(void)
{
    if (EXTI_State(Static_GPIO_INT, Static_PIN_INT))
    {
        EXTI_Clear(Static_GPIO_INT, Static_PIN_INT);
        //IRQ_Flag_TP = OK;
    }
}
#endif

/**
 * @brief   读取触摸点数据
 * @param   p_data : 触摸点数据
 * @param   points : 需要读取的触点个数
 * @retval  返回读取到的触点信息的个数
 */

uint8_t rtpx_read_points(tp_data_t *p_data, uint8_t points)
{
    uint8_t yl_min[2] = {0}, yl_max[2] = {0},  x_buf[2] = {0}, y_buf[2] = {0}, touch_points = 0, temp = 0, i = 0;
    uint16_t get_yl_min = 0, get_yl_max = 0, get_x = 0, get_y = 0;
    uint8_t buf[5] = {0};
    //读压力
    tp_read_regs(cmd_yl_min, &yl_min[0], 2);
    get_yl_min = yl_min[0];
    get_yl_min = (get_yl_min << 4) + (yl_min[1] >> 4);
    //printf(" cmd_yl_min   = [%d]\r\n", get_yl_min);
    //读压力
    tp_read_regs(cmd_yl_max, &yl_max[0], 2);
    get_yl_max = yl_max[0];
    get_yl_max = (get_yl_max << 4) + (yl_max[1] >> 4);
    //  printf(" cmd_yl_max   = [%d]\r\n", get_yl_max);
    if (get_yl_min >= 2528 && get_yl_max <= 3076) //压下
    {
        // printf(" 压下  \r\n");
        tp_read_regs(cmd_x, &x_buf[0], 2);          //读X值
        get_x = x_buf[0];
        get_x = (get_x << 4) + (x_buf[1] >> 4);
        if (get_x > 512)
        {
            get_x = get_x - 512;
            get_x = get_x / 6;
            if (get_x > 480)
            {
                get_x = 480;
            }
        }
        else
        {
            get_x = 0;
        }
        get_x = 480 - get_x;
        p_data[i].x = get_x; // x 坐标偏移
        // printf(" get_x   = [%d]\r\n", get_x);
        tp_read_regs(cmd_y, &y_buf[0], 2);          //读Y值
        get_y = y_buf[0];
        get_y = (get_y << 4) + (y_buf[1] >> 4);
        // printf(" get_y   = [%d]\r\n", get_y);
        if (get_y > 550)
        {
            get_y = get_y - 550;
            get_y = get_y / 10;
            if (get_y > 272)
            {
                get_y = 272;
            }
        }
        else
        {
            get_y = 0;
        }
        get_y = 272 - get_y;
        //printf(" get_y   = [%d]\r\n", get_y);
        p_data[i].y = get_y; /* y 坐标偏移 */
        p_data[i].event = TP_EVENT_PRESSED ;//;
    }
    else
    {
        p_data[i].x = 0; // x 坐标偏移
        p_data[i].y = 0; /* y 坐标偏移 */
        p_data[i].event = TP_EVENT_RELEASED;
        return 0;
    }
    return touch_points;
}

/*******************************************************************************************************************************************
 * Private Function
 *******************************************************************************************************************************************/
/**
 * @brief   iic 延时
 */
static void iic_delay(void)
{
    for (uint32_t i = 0; i < CyclesPerUs * 8; ++i)
        __NOP();
}

//写命令
//入口为命令
//出口为完成标志

/**
 * @brief   读取从机寄存器
 */
static uint8_t tp_read_regs(uint16_t reg, uint8_t *buf, uint8_t len)
{
    uint8_t i;
    uint8_t ack;
    ack = Static_IIC_Start(RTPx_ADDR | 0);
    if (ack == 0)
        goto rd_fail;
    ack = Static_IIC_Write(reg & 0XFF);
    if (ack == 0)
        goto rd_fail;
    iic_delay(); /* 此处必须延时等待一会再启动 */
    ack = Static_IIC_Start(RTPx_ADDR | 1); /* ReStart */
    if (ack == 0)
        goto rd_fail;
    for (i = 0; i < len - 1; i++)
    {
        buf[i] = Static_IIC_Read(1);
    }
    buf[i] = Static_IIC_Read(0);
    Static_IIC_Stop();
    iic_delay();
    return 0;
rd_fail:
    Static_IIC_Stop();
    iic_delay();
    return 1;
}

/**
 * @brief   写入从机寄存器
 */
static uint8_t tp_write_regs(uint16_t reg, uint8_t *buf, uint8_t len)
{
    uint32_t i;
    uint8_t ack;
    ack = Static_IIC_Start(RTPx_ADDR | 0);
    if (ack == 0)
        goto wr_fail;
    ack = Static_IIC_Write(reg & 0XFF);
    if (ack == 0)
        goto wr_fail;
    for (i = 0; i < len; i++)
    {
        ack = Static_IIC_Write(buf[i]);
        if (ack == 0)
            goto wr_fail;
    }
    Static_IIC_Stop();
    iic_delay();
    return 0;
wr_fail:
    Static_IIC_Stop();
    iic_delay();
    return 1;
}

#ifdef UPDATE_CFG
/**
 * @brief   更新触摸芯片配置
 */
static bool rtpx_update_cfg(void)
{
    uint8_t buf[2];
    uint8_t i = 0;
    /* set x range
    RTPx_CFG_Tab[2] = (uint8_t)(LCD_HDOT >> 8);
    RTPx_CFG_Tab[1] = (uint8_t)(LCD_HDOT & 0xff);
    */
    /* set y range
    RTPx_CFG_Tab[4] = (uint8_t)(LCD_VDOT >> 8);
    RTPx_CFG_Tab[3] = (uint8_t)(LCD_VDOT & 0xff);
    */
    /* change x y
    RTPx_CFG_Tab[6] ^= (1 << 3);
    */
    /* change int trig type */
    /* FLAG_INT_FALL_RX
    RTPx_CFG_Tab[6] &= 0xFC;
    RTPx_CFG_Tab[6] |= 0x01;
    */
    /* FLAG_RDONLY
    RTPx_CFG_Tab[6] &= 0xFC;
    RTPx_CFG_Tab[6] |= 0x03;
    */
    /* send config */
    if (tp_write_regs(RTPx_CFGS, RTPx_CFG_Tab, sizeof(RTPx_CFG_Tab)) != 0)
    {
        printf("send config failed\n");
        return false;
    }
    buf[0] = 0;
    for (i = 0; i < sizeof(RTPx_CFG_Tab); i++)
        buf[0] += RTPx_CFG_Tab[i];
    buf[0] = (~buf[0]) + 1;
    buf[1] = 1;
    tp_write_regs(RTPx_CHECK, buf, 2);
    Static_Delay_MS(10);
    printf("send config success\n");
    return true;
}
#endif
